package $4reflection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class $4_5_FnGetSuperClass {
    static final Logger logger = LoggerFactory.getLogger($4_5_FnGetSuperClass.class);
    public static void main(String[] args) throws Throwable {
        /**
         * 反射获取继承关系
         * 
         * 获取类：
         * 1、当我们获取到某个Class对象时，实际上就获取到了一个类的类型
         * 2、还可以用实例的getClass()方法获取
         * 3、通过Class.forName("")，传入Class的完整类名获取
         * 这三种方式获取的Class实例都是同一个实例，因为JVM对每个加载的Class只创建一个Class实例来表示它的类型。
         */
        // 获取到String的Class
        Class cls1 = String.class;
        // s是String，因此获取到String的Class
        String s = "";
        Class cls2 = s.getClass();
        // 通过Class.forName("")，传入Class的完整类名获取
        Class cls3 = Class.forName("java.lang.String");
        
        /**
         * 获取父类的Class
         * 
         */
        // 有了Class实例，我们还可以获取它的父类的Class
        Class i = Integer.class;
        Class n = i.getSuperclass();
        logger.info("i.getSuperclass() : {}", i.getSuperclass());
        // i.getSuperclass() : class java.lang.Number
        Class o = n.getSuperclass();
        logger.info("o : {}", o);
        // o : class java.lang.Object
        logger.info("o.getSuperclass() : {}", o.getSuperclass());
        // o.getSuperclass() : null
        
        // 除Object外，其他任何非interface的Class都必定存在一个父类类型。
        
        // 获取interface
        // 由于一个类可能实现一个或多个接口，通过Class我们就可以查询到实现的接口类型。例如，查询Integer实现的接口：
        Class cla = Integer.class;
        Class[] is = cla.getInterfaces();
        for (Class i1 : is) {
            logger.info("i1 : {}",i1);
        }
        logger.info("----优雅分割线----");
        // Integer实现的接口有：java.lang.Comparable、java.lang.constant.Constable、java.lang.constant.ConstantDesc
        // 要特别注意：getInterfaces()只返回当前类直接实现的接口类型，并不包括其父类实现的接口类型
        // 对所有interface的Class调用getSuperclass()返回的是null，获取接口的父接口要用getInterfaces()
        // 如果一个类没有实现任何interface，那么getInterfaces()返回空数组。
        Class clai = Integer.class.getSuperclass();
        Class[] iclai = clai.getInterfaces();
        for (Class i2 : iclai) {
            logger.info("i2 : {}",i2);
        }
        // Integer的父类是Number，Number实现的接口是java.io.Serializable。
        // 继承关系
        // 当我们判断一个实例是否是某个类型时，正常情况下，使用instanceof操作符：
        logger.info("----优雅分割线----");
        Object on = Integer.valueOf(123);
        logger.info("isDouble       : {}",on instanceof Double);    // false
        logger.info("isInteger      : {}",on instanceof Integer);   // true
        logger.info("isNumber       : {}",on instanceof Number);    // true
        logger.info("isSerializable : {}",on instanceof java.io.Serializable);  // true
        
        logger.info("----优雅分割线----");
        // 如果是两个Class实例，要判断一个向上转型是否成立，可以调用isAssignableFrom()：
        // Integer i = ?
        Integer.class.isAssignableFrom(Integer.class); // true，因为Integer可以赋值给Integer
        logger.info("Integer.class.isAssignableFrom(Integer.class) : {}",Integer.class.isAssignableFrom(Integer.class));
        // Number n = ?
        Number.class.isAssignableFrom(Integer.class); // true，因为Integer可以赋值给Number
        logger.info("Number.class.isAssignableFrom(Integer.class) : {}",Number.class.isAssignableFrom(Integer.class));
        // Object o = ?
        Object.class.isAssignableFrom(Integer.class); // true，因为Integer可以赋值给Object
        logger.info("Object.class.isAssignableFrom(Integer.class) : {}",Object.class.isAssignableFrom(Integer.class));
        // Integer i = ?
        Integer.class.isAssignableFrom(Number.class); // false，因为Number不能赋值给Integer
        logger.info("Integer.class.isAssignableFrom(Number.class) : {}",Integer.class.isAssignableFrom(Number.class));
        
        /**
         * 小结
         * 通过Class对象可以获取继承关系
         * Class getSuperclass()：获取父类类型；
         * Class[] getInterfaces()：获取当前类实现的所有接口。
         * 通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。
         */
    }

}
